package cn.springcloud.fix.uaa.web.service.impl;

import cn.springcloud.fix.common.cache.service.RedisService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.util.List;

/**
 * 自定义ClientDetailsService，减少数据库查询
 */
@Slf4j
@Service
public class MyClientDetailsService extends JdbcClientDetailsService {

    @Autowired
    private RedisService redisService;

    public MyClientDetailsService(DataSource dataSource) {
        super(dataSource);
    }

    @Override
    public ClientDetails loadClientByClientId(String clientId) {
        ClientDetails clientDetails = redisService.get(clientRedisKey(clientId));
        if (clientDetails == null) {
            clientDetails = cacheAndGetClient(clientId);
        }
        return clientDetails;
    }

    @Override
    public void removeClientDetails(String clientId) {
        super.removeClientDetails(clientId);
        removeRedisCache(clientId);
    }

    @Override
    public void updateClientSecret(String clientId, String secret) {
        super.updateClientSecret(clientId, secret);
        cacheAndGetClient(clientId);
    }

    @Override
    public void updateClientDetails(ClientDetails clientDetails) {
        super.updateClientDetails(clientDetails);
        cacheAndGetClient(clientDetails.getClientId());
    }

    /**
     * 缓存client并返回client
     */
    private ClientDetails cacheAndGetClient(String clientId) {
        try {
            ClientDetails clientDetails = super.loadClientByClientId(clientId);
            if (clientDetails != null) {
                redisService.set(clientRedisKey(clientId), clientDetails);
                log.info("缓存clientId:{},{}", clientId, JSON.toJSONString(clientDetails));
            }
            return clientDetails;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 删除redis缓存
     */
    private void removeRedisCache(String clientId) {
        redisService.deleteKey(clientRedisKey(clientId));
    }

    /**
     * 将oauth_client_details全表刷入redis，如果表数据量太大，则不用调该方法
     */
    public void loadAllClientToCache() {
        List<ClientDetails> list = super.listClientDetails();
        if (CollectionUtils.isEmpty(list)) {
            log.error("oauth_client_details表数据为空，请检查");
            return;
        }
        list.forEach(client -> redisService.set(clientRedisKey(client.getClientId()), client));
    }

    private String clientRedisKey(String clientId) {
        return "oauth_client_details:" + clientId;
    }
}
